<?php

namespace app\admin\controller;

use app\admin\library\Auth;
use app\admin\model\AdminLog;
use app\common\controller\Base;
use think\Db;

class Backend extends Base
{
    /**
     * @var bool
     * 是否开启数据验证
     */
    protected $openValidate = true;

    /**
     * @var string
     * 定义数据表的名称
     */
    protected $tableName = '';

    /**
     * @var string
     * 定义数据表对应的模型名称
     */
    protected $modelName = '';

    /**
     * @var string
     * 页面访问的模式
     * tabs：添加标签页
     * dialog：弹窗
     * blank：新页面
     */
    protected $layout = 'tabs';

    /**
     * @var string
     * 快速搜索的时候查询的字段，支持逗号分隔的字符串或数组
     */
    protected $searchFields = 'id';

    /**
     * @var array
     * 不需要权限认证的控制器/方法（*表示该控制器的所有方法都不需要权限认证）
     */
    protected $noNeedAuth = [];

    /**
     * @var array
     * 不需要登录就能访问
     */
    protected $noNeedLogin = [];

    /**
     * @var Auth
     * 权限控制实例
     */
    protected $auth = null;


    /**
     * @var string
     * 当前访问的控制器/方法组成的规则名称
     */
    protected $ruleName = '';

    /**
     * @var int   频率，单位毫秒，0表示不开启
     * 轮询方式获取系统通知的频率
     */
    protected $notificationTimer = 10000;

    public function initialize()
    {
        parent::initialize();

        //设置链接根目录
        $this->assign('root', $this->request->root());
        
        //页面的查看模式
        $this->layout = input('param._ref', 'tabs');
        if (!in_array($this->layout, ['tabs', 'dialog'])) {
            $this->layout = 'tabs';
        }
        $this->assign('layout', $this->layout);

        //确定默认的表名称和模型名称
        $controller = $this->request->controller();
        if (empty($this->tableName)) {
            $this->tableName = parse_camel_to_lower($controller);
        }
        if (empty($this->modelName)) {
            $this->modelName = $controller;
        }

        $this->ruleName = parse_camel_to_lower($controller) . '/' . $this->request->action();
        $this->auth = Auth::getInstance($this->noNeedAuth);

        //验证登录
        if (!$this->isNoNeedLogin() && (!$this->auth->isLogin() && !$this->auth->autoLogin())) {
            $this->error('还未登录', 'login/index');
        }

        //权限验证
        if (!$this->auth->check($this->ruleName)) {
            $this->error('无权访问');
        }

        $this->assign('auth', $this->auth);

        //$currentMenu = $this->auth->getDataByRuleName($this->ruleName);
        // halt($currentMenu);

    }

    /**
     * 检测当前访问的地址是否是不需要登录的
     * @return bool
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/20 17:21
     * Note:
     */
    protected function isNoNeedLogin()
    {
        $rule_name = strtolower($this->request->controller() . '/' . $this->request->action());
        if (empty($this->noNeedLogin)) {
            return false;
        }

        $noNeedLogin = array_map('strtolower', $this->noNeedLogin);

        if (in_array('*', $this->noNeedLogin) || in_array($rule_name, $noNeedLogin)) {
            return true;
        }

        return false;
    }


    /**
     * 构建查询所需要的一些参数
     * @param array|string $searchFields  快速查询的多个字段名称
     * @return array
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/16 19:29
     * Note:
     */
    protected function buildSearchParams($searchFields = null)
    {
        //分页
        $offset = input('offset/d', 0);
        $limit = input('limit/d', 10);
        $page = $limit ? floor($offset / $limit) + 1 : 1;

        //排序
        $sort = input('sort/s', 'id');
        $order = strtoupper(input('order/s', 'DESC'));
        $order = in_array($order, ['ASC', 'DESC']) ? $order : 'DESC';

        //查询条件
        $where = [];
        $searchFields = is_null($searchFields) ? $this->searchFields : $searchFields;
        $searchFields = is_array($searchFields) ? $searchFields : explode(',', $searchFields);
        $search = input('search/s', '', 'trim');
        $filter = input('filter/s', '{}', 'trim');
        $operate = input('operate/s', '{}', 'trim');
        $filter = (array)json_decode(urldecode($filter), true);
        $operate = (array)json_decode(urldecode($operate), true);

        if (!empty($search)) {
            $where[] = [implode('|', $searchFields), 'like', '%' . $search . '%'];
        }

        foreach ($filter as $field => $value) {
            if (!preg_match('/^[a-zA-Z0-9_\.]+$/', $field)) {
                continue;
            }

            $op = isset($operate[$field]) && !empty($operate[$field]) ? strtoupper(trim($operate[$field])) : '=';

            $vl = trim($value);
            switch ($op) {
                case '=':
                case '<>':
                case '> TIME':
                case '>= TIME':
                case '< TIME':
                case '<= TIME':
                    $where[] = [$field, $op, $vl];
                    break;
                case '>':
                case '>=':
                case '<=':
                    $where[] = [$field, $op, intval($vl)];
                    break;
                case 'LIKE':
                case 'NOT LIKE':
                    $where[] = [$field, $op, "%{$vl}%"];
                    break;
                case 'IN':
                case 'NOT IN':
                    $where[] = [$field, $op, is_array($vl) ? $vl : explode(',', $vl)];
                    break;
                case 'BETWEEN':
                case 'NOT BETWEEN':
                    $where[] = [$field, $op, "{$vl}"];
                    break;
                case 'BETWEEN TIME':
                case 'NOT BETWEEN TIME':
                    if (false !== strpos($vl, ' - ')) {
                        $where[] = [$field, $op, explode(' - ', $vl)];
                    } else if (!empty($vl)) {
                        $where[] = [$field, '=', $vl];
                    }
                    break;
                case 'NULL':
                case 'IS NULL':
                case 'NOT NULL':
                case 'IS NOT NULL':
                    $where[] = [$field, strtolower(str_replace('IS ', '', $op))];
                    break;
                default:
                    //LIKE查询支持更复杂一点的查询，格式(LIKE %...% 或 _..._ 等，总之中间必须是...表示要替换的查询关键词)
                    if (preg_match('/^LIKE (_*|%?)\.{3}(_*|%?)$/i', $op)) {
                        $where[] = [$field, 'LIKE', str_replace('...', $value, ltrim($op, 'LIKE '))];
                    } elseif (preg_match('/^NOT LIKE (_*|%?)\.{3}(_*|%?)$/i', $op)) {
                        $where[] = [$field, 'NOT LIKE', str_replace('...', $value, ltrim($op, 'NOT LIKE '))];
                    }
                    break;
            }
        }


        return [$where, $sort, $order, $page, $offset, $limit];
    }

    /**
     * 通用的数据列表页
     * @return mixed|\think\response\Json
     * @throws \think\exception\DbException
     * Author: LCY<409028735@qq.com>
     * Time: 2021/12/2 17:17
     * Note:
     */
    public function index()
    {
        if ($this->request->isAjax()) {
            list($where, $sort, $order, $page, $offset, $limit) = $this->buildSearchParams($this->searchFields);
            $rows = Db::name($this->tableName)->where($where)->order($sort, $order)->paginate([
                'list_rows' => $limit,
                'page' => $page,
            ]);
            $data = [
                'total' => $rows->total(),
                'rows' => $rows->items(),
            ];
            return json($data);
        }
        return $this->fetch();
    }

    /**
     * 通用添加
     * @return mixed
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/30 10:47
     * Note:
     */
    public function add()
    {
        if ($this->request->isPost()) {
            //获取提交的数据
            $data = input('post.');
            //验证token

            //表单验证
            $this->validate_response($data, $this->modelName . '.add');

            //保存到数据库
            try {
                $res = model($this->modelName)->allowField(true)->save($data);
            } catch (\Exception $e) {
                $this->error('添加失败：' . $e->getMessage());
            }

            if (!$res) {
                $this->error('添加失败，请重试');
            }

            $this->success('添加完成');
        }

        return $this->fetch();
    }

    /**
     * 通用修改
     * @return mixed
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/30 10:56
     * Note:
     */
    public function edit()
    {
        if ($this->request->isPost()) {
            //获取提交的数据
            $data = input('post.');
            //验证token

            //表单验证
            $this->validate_response($data, $this->modelName . '.edit');

            //保存到数据库
            try {
                $res = model($this->modelName)->allowField(true)->isUpdate(true)->save($data);
            } catch (\Exception $e) {
                $this->error('修改失败：' . $e->getMessage());
            }

            if (false === $res) {
                $this->error('修改失败，请重试');
            }

            $this->success('修改完成');
        }

        $id = input('param.id/d', 0);
        try {
            $info = model($this->modelName)->findOrEmpty($id);
        } catch (\Exception $e) {
            $this->error('修改失败：' . $e->getMessage());
        }

        if (empty($info)) {
            $this->error('数据不存在');
        }

        $this->assign('info', $info);
        return $this->fetch();
    }

    /**
     * 通用删除
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/30 10:59
     * Note:
     */
    public function del()
    {
        if ($this->request->isPost()) {
            $ids = input('ids/s', '');
            if (empty($ids)) {
                $this->error('还未选择要删除的数据');
            }
            try {
                $res = model($this->modelName)->where('id', 'in', $ids)->delete();
            } catch (\Exception $e) {
                $this->error('修改失败：' . $e->getMessage());
            }

            if (!$res) {
                $this->error('删除失败，请重试');
            }

            $this->success('删除完成');
        }
    }

    /**
     * 查看数据详情页
     * @return mixed
     * Author: LCY<409028735@qq.com>
     * Time: 2021/12/2 16:33
     * Note:
     */
    public function detail()
    {
        $id = input('id/d', 0);
        if (empty($id)) {
            $this->error('查看的内容参数有误');
        }
        try {
            $res = model($this->modelName)->get($id);
        } catch (\Exception $e) {
            $this->error('查看失败：' . $e->getMessage());
        }

        if (!$res) {
            $this->error('查看的数据不存在');
        }

        $this->assign('info', $res);
        return $this->fetch();
    }

    /**
     * 通用的批量操作
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/30 11:06
     * Note:
     */
    public function multi()
    {
        if ($this->request->isPost()) {
            $ids = input('post.ids/s', 0);
            $field = input('post.field/s', '');
            $value = input('post.value/s', '');
            if (empty($ids) || empty($field)) {
                $this->error('参数有误');
            }

            try {
                $res = model($this->modelName)->where('id', 'in', $ids)->setField($field, $value);
            } catch (\Exception $e) {
                $this->error('设置失败：' . $e->getMessage());
            }

            if (false === $res) {
                $this->error('设置失败，请重试');
            }

            $this->success('设置完成');
        }
    }

    /**
     * 通用的切换设置
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/30 18:40
     * Note:
     */
    public function toggle()
    {
        if ($this->request->isPost()) {
            $ids = input('post.ids/d', 0);
            $field = input('post.field/s', '');
            $value = input('post.value/s', '');
            if (empty($ids) || empty($field)) {
                $this->error('参数有误');
            }

            try {
                $res = model($this->modelName)->where('id', 'in', $ids)->setField($field, $value);
            } catch (\Exception $e) {
                $this->error('设置失败：' . $e->getMessage());
            }

            if (false === $res) {
                $this->error('设置失败，请重试');
            }

            $this->success('设置完成');
        }
    }

    /**
     * 通用设置排序值
     * Author: LCY<409028735@qq.com>
     * Time: 2021/11/30 10:27
     * Note:
     */
    public function sort()
    {
        if ($this->request->isPost()) {
            $id = input('post.id/d', 0);
            $sort = input('post.sort/d', 0);
            if (empty($id)) {
                $this->error('ID参数有误');
            }
            if ($sort < 0 || $sort > 10000) {
                $this->error('排序设置范围：0 ~ 10000 之间');
            }
            try {
                $res = Db::name($this->tableName)->where('id', $id)->setField('sort', $sort);
            } catch (\Exception $e) {
                $this->error('修改失败：' . $e->getMessage());
            }

            $this->success('设置完成');
        }
    }

    /**
     * 写入操作日志
     * @param string $title  操作名称
     * @param string $desc   操作描述
     * @param array $data   提交的数据
     * Author: LCY<409028735@qq.com>
     * Time: 2021/4/22 10:17
     * Note:
     */
    protected function writeAdminLog($title = '', $desc = '', $data = [])
    {
        //已手动写入日志的标记，如果手动写入日志，在中间件中就不写日志了
        $this->request->hasWriteLog = true;

        AdminLog::saveAdminLog($this->auth->id, $title, $desc, $data);
    }
}
